//
//  HFCaptureWindowController.m
//  HocusFocus
//
//  Created by Juan Carlos Jimenez on 4/6/08.
//  Copyright 2008 Juan Carlos Jimenez. All rights reserved.
//
#import <QuartzCore/QuartzCore.h>
#import "HFCaptureWindowController.h"
#import "HFCaptureView.h"
#import "HFOpenGLCapturer.h"
#import "HFCaptureSession.h"
#import "HFBezierPathOrnament.h"
#import "HFOrnamentView.h"
#import "HFGraphicProperties.h"

static NSSound *grabSound;

@interface HFCaptureWindowController ()
@property (readwrite,assign) HFCaptureSession *captureSession;
@end

@implementation HFCaptureWindowController

@synthesize ornaments;
@synthesize inspectorPanel;
@synthesize paletteView;
@synthesize paletteContainer;
@synthesize ornamentArrayController;

+ (void) initialize
{
    grabSound = [[NSSound alloc] initWithContentsOfFile:@"/System/Library/Components/CoreAudio.component/Contents/Resources/SystemSounds/system/Grab.aif" byReference:YES];
}

- (id)init
{
	return [super initWithWindowNibName:@"HFCaptureWindow"];
}

- (void) dealloc
{
    self.inspectorPanel = nil;
    self.paletteView = nil;
    self.ornamentArrayController = nil;
    self.ornaments = nil;
    [super dealloc];
}

- (HFCaptureWindow *)captureWindow
{
    return (HFCaptureWindow *)[self window];
}

- (HFCaptureView *)captureView
{
    return (HFCaptureView *)[[self captureWindow] contentView];
}

- (HFCaptureSession *)captureSession
{
    return self.captureView.captureSession;
}

- (void)setCaptureSession:(HFCaptureSession *)session
{
    self.captureView.captureSession = session;
}

- (HFOrnament *)selectedOrnament
{
    return [self.ornaments objectAtIndex:[[self.paletteView selectionIndexes] firstIndex]];
}

- (NSData *)pasteboardDataForImage:(NSImage *)image
{
	NSBitmapImageRep *bitmap = [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
	return [bitmap representationUsingType:NSPNGFileType properties:nil];
}

- (void)performCaptureWithSession:(HFCaptureSession *)session
{
    NSImage *image;
    NSData *imageData;
    NSPasteboard *pasteboard; 
    NSRect r = [[session captureArea] rect];
    NSRect sr = [[self window] frame];
    
    r.origin = [[self window] convertBaseToScreen:r.origin];
    image = [[HFOpenGLCapturer sharedInstance] captureImageRect:r forScreenRect:sr];
    imageData = [self pasteboardDataForImage:image];
    pasteboard = [NSPasteboard generalPasteboard];
    [pasteboard declareTypes:[NSArray arrayWithObjects:NSTIFFPboardType, nil] owner:nil];
    [pasteboard setData:imageData forType:NSTIFFPboardType];
}

- (void)handleCaptureDidDefineCaptureArea:(NSNotification *)notification
{
    HFCaptureSession *captureSession = (HFCaptureSession *)[[notification userInfo] objectForKey:@"captureSession"];
    NSRect r = captureSession.captureArea.rect;
    NSRect sr = [self.captureWindow frame];
    
    r.origin = [self.captureWindow convertBaseToScreen:r.origin];
    CGFloat newx;
    CGFloat newy;
    
    newx = r.origin.x - [inspectorPanel frame].size.width - 8.0;
    if (newx < sr.origin.x) {
        newx = NSMaxX(r) + 8.0;
        if ((newx + [self.paletteView bounds].size.width) > NSMaxX(sr)) {
            newx = sr.origin.x;
        }
    }
    newy = NSMaxY(r) - [inspectorPanel frame].size.height;
    if (newy < sr.origin.y) {
        newy = sr.origin.y;
    }
    [inspectorPanel setFrameOrigin:NSMakePoint(newx, newy)];
    [inspectorPanel setLevel:NSScreenSaverWindowLevel + 1];
    [inspectorPanel orderFront:self];
    [self.captureView.cursorInfoWindow orderOut:self];
}

- (void)handleCaptureEndNotification:(NSNotification *)notification
{
    HFCaptureSession *captureSession = (HFCaptureSession *)[[notification userInfo] objectForKey:@"captureSession"];

    [self.inspectorPanel orderOut:self];
	if ([captureSession hasValidCaptureArea]) {
        [self performCaptureWithSession:captureSession];
        [grabSound play];
	}
    [self.captureWindow setIsVisible:NO];
    [self.captureWindow orderOut:self];
    [self.captureView.cursorInfoWindow orderOut:self];
	[captureSession reset];
}

- (void)handleCaptureCancelNotification:(NSNotification *)notification
{
    HFCaptureSession *captureSession = (HFCaptureSession *)[[notification userInfo] objectForKey:@"captureSession"];

    [self.inspectorPanel orderOut:self];
    [self.captureWindow setIsVisible:NO];
    [self.captureWindow orderOut:self];
    [self.captureView.cursorInfoWindow orderOut:self];
	[captureSession reset];
}

- (void)windowDidLoad
{
	[super windowDidLoad];
	
    self.ornaments = [[[NSMutableArray alloc] init] autorelease];

    [self.captureWindow setDelegate:self];
	[self.captureWindow setHasShadow:NO];
    [self.captureWindow setOpaque:NO];
	[self.captureWindow setBackgroundColor:[NSColor clearColor]];
	[self.captureWindow setMovableByWindowBackground:NO];
	[self.captureWindow setIgnoresMouseEvents:NO];
	[self.captureWindow setAcceptsMouseMovedEvents:YES];
    
    [self.inspectorPanel setStyleMask:NSBorderlessWindowMask];
    [self.inspectorPanel setOpaque:NO];
    [self.inspectorPanel setBackgroundColor:[NSColor clearColor]];

    NSRect r = NSMakeRect(0, 0, 100, 100);
    NSBezierPath *humanOval;
    NSBezierPath *oval = [NSBezierPath bezierPathWithOvalInRect:r];
    NSBezierPath *rectangle = [NSBezierPath bezierPathWithRect:r];
    NSBezierPath *roundRectangle = [NSBezierPath bezierPathWithRoundedRect:r xRadius:8.0 yRadius:8.0];
    NSBezierPath *rightArrow;
    NSBezierPath *leftArrow;
    
    humanOval = [NSBezierPath bezierPath];
	[humanOval moveToPoint:NSMakePoint(r.origin.x + (r.size.width * 0.85), r.origin.y + (r.size.height * 0.95))];
	// Upper-left line
	[humanOval curveToPoint:NSMakePoint(r.origin.x, r.origin.y + (r.size.height * 0.5))
               controlPoint1:NSMakePoint(r.origin.x + (r.size.width * 0.25), r.origin.y + (r.size.height * 0.95))
               controlPoint2:NSMakePoint(r.origin.x + (r.size.width * 0.00), r.origin.y + (r.size.height * 0.80))];
	// Left line
	[humanOval curveToPoint:NSMakePoint(r.origin.x + (r.size.width * 0.50), r.origin.y)
               controlPoint1:NSMakePoint(r.origin.x + (r.size.width * 0.00), r.origin.y + (r.size.height * 0.25))
               controlPoint2:NSMakePoint(r.origin.x + (r.size.width * 0.25), r.origin.y + (r.size.height * 0.0))];
	// Lower line
	[humanOval curveToPoint:NSMakePoint(r.origin.x + r.size.width,          r.origin.y + (r.size.height * 0.5))
               controlPoint1:NSMakePoint(r.origin.x + (r.size.width * 0.75), r.origin.y + (r.size.height * 0.0))
               controlPoint2:NSMakePoint(r.origin.x + (r.size.width * 1.00), r.origin.y + (r.size.height * 0.25))];
	// Right line
	[humanOval curveToPoint:NSMakePoint(r.origin.x + (r.size.width * 0.65), r.origin.y + (r.size.height * 0.90))
               controlPoint1:NSMakePoint(r.origin.x + (r.size.width * 1.00), r.origin.y + (r.size.height * 0.80))
              controlPoint2:NSMakePoint(r.origin.x + (r.size.width * 0.85), r.origin.y + (r.size.height * 0.85))];
    
    rightArrow = [NSBezierPath bezierPath];
    [rightArrow moveToPoint:NSMakePoint(r.origin.x, r.origin.y + (r.size.height * 0.25))];
    [rightArrow lineToPoint:NSMakePoint(r.origin.x, r.origin.y + (r.size.height * 0.75))];
    [rightArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y + (r.size.height * 0.75))];
    [rightArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y + (r.size.height))];
    [rightArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width,        r.origin.y + (r.size.height * 0.5))];
    [rightArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y)];
    [rightArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, (r.origin.y + r.size.height * 0.25))];
    [rightArrow closePath];
    [rightArrow setMiterLimit:2.5];
    
    leftArrow = [NSBezierPath bezierPath];
    [leftArrow moveToPoint:NSMakePoint(r.origin.x,                       r.origin.y + (r.size.height * 0.5))];
    [leftArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y)];
    [leftArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y + (r.size.height * 0.25))];
    [leftArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width,        r.origin.y + (r.size.height * 0.25))];
    [leftArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width,        r.origin.y + (r.size.height * 0.75))];
    [leftArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y + (r.size.height * 0.75))];
    [leftArrow lineToPoint:NSMakePoint(r.origin.x + r.size.width * 0.50, r.origin.y + r.size.height)];
    [leftArrow closePath];
    [leftArrow setMiterLimit:2.5];
    
    [ornamentArrayController addObjects:[NSArray arrayWithObjects:[[[HFBezierPathOrnament alloc] initWithBezier:humanOval inRect:r] autorelease],
                                                                  [[[HFBezierPathOrnament alloc] initWithBezier:oval inRect:r] autorelease],
                                                                  [[[HFBezierPathOrnament alloc] initWithBezier:rectangle inRect:r] autorelease],
                                                                  [[[HFBezierPathOrnament alloc] initWithBezier:roundRectangle inRect:r] autorelease],
                                                                  [[[HFBezierPathOrnament alloc] initWithBezier:rightArrow inRect:r] autorelease],
                                                                  [[[HFBezierPathOrnament alloc] initWithBezier:leftArrow inRect:r] autorelease],
                                                                  nil]];
    HFBezierPathOrnament *rightArrowOrnament = (HFBezierPathOrnament *)[self.ornaments objectAtIndex:4];
    HFBezierPathOrnament *leftArrowOrnament = (HFBezierPathOrnament *)[self.ornaments objectAtIndex:5];
    
    rightArrowOrnament.graphicProperties.fillColor = leftArrowOrnament.graphicProperties.strokeColor;
    leftArrowOrnament.graphicProperties.fillColor = leftArrowOrnament.graphicProperties.strokeColor;

    [self.paletteView addObserver:self forKeyPath:@"selectionIndexes" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
    
    [self.paletteView setMaxItemSize:NSMakeSize(64, 64)];
    [self.paletteView setMinItemSize:NSMakeSize(64, 64)];
    [self.paletteContainer sizeToFit];

	[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleCaptureEndNotification:)
                                                 name:kHFCaptureDoneNotification
                                               object:self.captureView];
	[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleCaptureCancelNotification:)
                                                 name:kHFCaptureCancelNotification
                                               object:self.captureView];
	[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleCaptureDidDefineCaptureArea:)
                                                 name:kHFCaptureDidDefineCaptureAreaNotification
                                               object:self.captureView];

    self.captureView.captureSession = [[[HFCaptureSession alloc] init] autorelease];

    [self.paletteView setSelectionIndexes:[NSIndexSet indexSetWithIndex:0]];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqual:@"selectionIndexes"]) {
        NSIndexSet *selectionIndexes = (NSIndexSet *)[change objectForKey:NSKeyValueChangeNewKey];
        
        if ([selectionIndexes count] > 0) {
            self.captureSession.currentOrnament = [self.ornaments objectAtIndex:[selectionIndexes firstIndex]];
        }
    }
}

- (void)scrollWheel:(NSEvent *)event
{
    if ([event deltaY] != 0.0) {
        NSIndexSet *selection = [self.paletteView selectionIndexes];
        NSUInteger selectedIndex = [selection firstIndex];
        NSUInteger lastIndex = [[self.paletteView subviews] count] - 1;
        
        if ([event deltaY] < 0.0) {
            selectedIndex++;
            if (selectedIndex > lastIndex) {
                selectedIndex = 0;
            }
        } else {
            if (selectedIndex == 0) {
                selectedIndex = lastIndex;
            } else {
                selectedIndex--;
            }
        }
        [self.paletteView setSelectionIndexes:[NSIndexSet indexSetWithIndex:selectedIndex]];
    }
}

- (void)handleHotKey:(NSEvent *)event
{
    NSRect screenFrame = NSZeroRect;
    BOOL first = YES;
    
    for (NSScreen *screen in [NSScreen screens]) {
        if (first) {
            screenFrame = [screen frame];
            first = NO;
        } else {
            screenFrame = NSUnionRect(screenFrame, [screen frame]);
        }
    }
    [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
    [self.captureWindow setFrame:screenFrame display:YES];
	[self.captureWindow setLevel:NSScreenSaverWindowLevel];
    [[self.captureWindow contentView] setNeedsDisplay:YES];
	[self.captureWindow makeKeyAndOrderFront:self];
    [self.captureWindow makeFirstResponder:self.captureView];
    [self.captureView updateCursorPosition:[NSEvent mouseLocation] withDisplay:[self.captureView displayPointForScreenPoint:[NSEvent mouseLocation]]];
	[self.captureView.cursorInfoWindow setLevel:NSScreenSaverWindowLevel];
    [self.captureView.cursorInfoWindow orderFront:self];
}

- (void)cancelOperation:(id)sender
{
    [self.captureView postCaptureDidCancelNotification];
}

@end

